import React, { useEffect, useMemo, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { useDanmakuRendererEventListener, useApiQueryDanmaku } from '@/hooks';
import { DanmakuRenderer } from '../danmaku';
import { queryDanmakuConfig } from '@/api';
import type { ISMap } from '../map-kit';
import type { IDanmakuImage, IDanmakuOptions, IDanmakuRenderer, IDanmakuRendererOptions } from '../danmaku';
import { MapEventType } from 'mapbox-gl';

type IMapDanmakuProps = Omit<IDanmakuRendererOptions, 'danmakuImages'> & {
  map?: ISMap;
  height?: number;
  style?: React.CSSProperties;
  onReady?: (danmakuRenderer: IDanmakuRenderer) => void;
  genDanmakus?: (d: IDanmakuImage[]) => Promise<IDanmakuOptions[]>;
};

export const MapDanmaku = (props: IMapDanmakuProps) => {
  const { map, height, onReady, style, ...restProps } = props;
  const [danmakuRenderer, setDanmakuRenderer] = useState<IDanmakuRenderer>();
  const [danmakuEnabled, setDanmakuEnabled] = useState<boolean>();
  const { run } = useApiQueryDanmaku();
  const containerRef = useRef<HTMLDivElement>(null);
  const internalHeight = useMemo(() => {
    if (height) return height;
    return Math.ceil(height || document.body.getBoundingClientRect().height / 3);
  }, [height]);

  useDanmakuRendererEventListener(danmakuRenderer?.event, 'enabled', ({ enabled }) => {
    setDanmakuEnabled(enabled);
  });

  useEffect(() => {
    const init = async () => {
      const res = await queryDanmakuConfig();
      if (Array.isArray(res?.data?.data)) {
        const d = new DanmakuRenderer({ danmakuImages: res.data.data, container: containerRef.current!, ...restProps });
        if (map) map.addModule({ name: 'danmakuRenderer', value: d });
        if (typeof onReady === 'function') onReady(d);
        setDanmakuRenderer(d);
      }
    };
    if (map) init();
  }, [map]);

  useEffect(() => {
    const listenMapMoveend = async (e: MapEventType['zoomend']) => {
      const res = await run({ bbox: e.target.getBounds().toArray().flat() }, { silent: true });
      if (Array.isArray(res?.data)) {
        map!.danmakuRenderer.setDanmakus(res.data.map((v) => ({ ...v, time: new Date(v.time).valueOf() })));
      }
    };

    if (map) map.on('moveend', listenMapMoveend);
    return () => {
      map?.off('moveend', listenMapMoveend);
    };
  }, [danmakuEnabled]);

  return createPortal(
    <div style={{ position: 'absolute', top: 0, width: '100%', height: internalHeight, ...style }} ref={containerRef} />,
    document.body,
  );
};
